agora inbox for [email protected]
help / color / mirror / Atom feedSpeeding up operations
802+ messages / 8 participants
[nested] [flat]
* Speeding up operations
@ 2003-08-13 05:23 Rahul_Iyer <[email protected]>
2003-08-13 19:47 ` Re: Speeding up operations Frank Wiles <[email protected]>
2003-08-13 19:47 ` Re: Speeding up operations Rod Taylor <[email protected]>
2003-08-13 20:26 ` Re: Speeding up operations Tom Lane <[email protected]>
2003-08-13 22:42 ` Re: Speeding up operations Hannu Krosing <[email protected]>
0 siblings, 4 replies; 802+ messages in thread
From: Rahul_Iyer @ 2003-08-13 05:23 UTC (permalink / raw)
To: pgsql-hackers
hi...
im on a project using Postgres. The project involves, at times, upto
5,000,000 inserts. I was checking the performance of Postgres for 5M inserts
into a 2 column table (one col=integer, 2nd col=character). I used the
Prepare... and execute method, so i basically had 5M execute statements and
1 prepare statement. Postgres took 144min for this... is there any way to
improve this performance? if so, how? btw, im using it on a SPARC/Solaris
2.6.
thanx in adv
rahul
P.S: Kindly point me towards any relevant documentation as well.
^ permalink raw reply [nested|flat] 802+ messages in thread
* Re: Speeding up operations
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
@ 2003-08-13 19:47 ` Frank Wiles <[email protected]>
3 siblings, 0 replies; 802+ messages in thread
From: Frank Wiles @ 2003-08-13 19:47 UTC (permalink / raw)
To: Rahul_Iyer <[email protected]>; +Cc: pgsql-hackers
On Wed, 13 Aug 2003 10:53:39 +0530
"Rahul_Iyer" <[email protected]> wrote:
> hi...
> im on a project using Postgres. The project involves, at times, upto
> 5,000,000 inserts. I was checking the performance of Postgres for 5M
> inserts into a 2 column table (one col=integer, 2nd col=character). I
> used the Prepare... and execute method, so i basically had 5M execute
> statements and 1 prepare statement. Postgres took 144min for this...
> is there any way to improve this performance? if so, how? btw, im
> using it on a SPARC/Solaris 2.6.
> thanx in adv
> rahul
>
> P.S: Kindly point me towards any relevant documentation as well.
If this is a one time insert you'll want to remove any indexes
and rebuild them after the inserts are done.
Also you'll want to look into the COPY command here:
http://www.postgresql.org/docs/7.3/static/sql-copy.html
Loading the data from file like this is probably going to be much
faster than from a script and/or program.
---------------------------------
Frank Wiles <[email protected]>
http://frank.wiles.org
---------------------------------
^ permalink raw reply [nested|flat] 802+ messages in thread
* Re: Speeding up operations
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
@ 2003-08-13 19:47 ` Rod Taylor <[email protected]>
3 siblings, 0 replies; 802+ messages in thread
From: Rod Taylor @ 2003-08-13 19:47 UTC (permalink / raw)
To: Rahul_Iyer <[email protected]>; +Cc: pgsql-hackers
> im on a project using Postgres. The project involves, at times, upto
> 5,000,000 inserts. I was checking the performance of Postgres for 5M inserts
> into a 2 column table (one col=integer, 2nd col=character). I used the
> Prepare... and execute method, so i basically had 5M execute statements and
> 1 prepare statement. Postgres took 144min for this... is there any way to
> improve this performance? if so, how? btw, im using it on a SPARC/Solaris
> 2.6.
7.4 beta2 will help -- when it comes out.
The fastest method will still be COPY.
Attachments:
[application/pgp-signature] signature.asc (187B, ../../1060804075.11688.73.camel@jester/2-signature.asc)
download
^ permalink raw reply [nested|flat] 802+ messages in thread
* Re: Speeding up operations
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
@ 2003-08-13 20:26 ` Tom Lane <[email protected]>
3 siblings, 0 replies; 802+ messages in thread
From: Tom Lane @ 2003-08-13 20:26 UTC (permalink / raw)
To: Rahul_Iyer <[email protected]>; +Cc: pgsql-hackers
"Rahul_Iyer" <[email protected]> writes:
> im on a project using Postgres. The project involves, at times, upto
> 5,000,000 inserts. I was checking the performance of Postgres for 5M inserts
> into a 2 column table (one col=integer, 2nd col=character). I used the
> Prepare... and execute method, so i basically had 5M execute statements and
> 1 prepare statement. Postgres took 144min for this... is there any way to
> improve this performance?
COPY, perhaps. Have you read
http://www.postgresql.org/docs/view.php?version=7.3&idoc=0&file=populate.html
regards, tom lane
^ permalink raw reply [nested|flat] 802+ messages in thread
* Re: Speeding up operations
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
@ 2003-08-13 22:42 ` Hannu Krosing <[email protected]>
2003-08-14 16:47 ` Re: Speeding up operations Matthew T. O'Connor <[email protected]>
3 siblings, 1 reply; 802+ messages in thread
From: Hannu Krosing @ 2003-08-13 22:42 UTC (permalink / raw)
To: Rahul_Iyer <[email protected]>; +Cc: pgsql-hackers
Rahul_Iyer kirjutas K, 13.08.2003 kell 08:23:
> hi...
> im on a project using Postgres. The project involves, at times, upto
> 5,000,000 inserts. I was checking the performance of Postgres for 5M inserts
> into a 2 column table (one col=integer, 2nd col=character). I used the
> Prepare... and execute method, so i basically had 5M execute statements and
> 1 prepare statement. Postgres took 144min for this... is there any way to
> improve this performance? if so, how? btw, im using it on a SPARC/Solaris
> 2.6.
If you are inserting into an empty table with primary key (or other
constraints), you can run ANALYZE on that table in 1-2 minutes after you
have started the INSERTs, so that constraint-checking logic will do the
right thing (use inedex for pk).
in my tests I achieved about 9000 inserts/sec by using multiple
inserting frontends and ~100 inserts per transaction (no indexes, 6
columns, 4 processors, 2GB memory, test clients running on same
computer)
--------------
Hannu
^ permalink raw reply [nested|flat] 802+ messages in thread
* Re: Speeding up operations
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
2003-08-13 22:42 ` Re: Speeding up operations Hannu Krosing <[email protected]>
@ 2003-08-14 16:47 ` Matthew T. O'Connor <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Matthew T. O'Connor @ 2003-08-14 16:47 UTC (permalink / raw)
To: Hannu Krosing <[email protected]>; Rahul_Iyer <[email protected]>; +Cc: pgsql-hackers
----- Original Message -----
From: "Hannu Krosing" <[email protected]>
> If you are inserting into an empty table with primary key (or other
> constraints), you can run ANALYZE on that table in 1-2 minutes after you
> have started the INSERTs, so that constraint-checking logic will do the
> right thing (use inedex for pk).
This is one of the things that pg_autovaccum attempts to do. If you are
doing a lot of inserts into a table, it will perform periodic analyze
commands. The threshold for performing analyze is much lower than the
threshold for vacuum. Also, inserts don't effect the count towards the
vacuum threshold, only the analyze threshold.
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v3 1/1] Use C99-designated initializer syntax for dispatch_table array
@ 2024-03-05 13:32 Japin Li <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Japin Li @ 2024-03-05 13:32 UTC (permalink / raw)
---
src/backend/executor/execExprInterp.c | 203 ++++++++++++--------------
src/include/executor/execExpr.h | 2 +-
2 files changed, 97 insertions(+), 108 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 7c1f51e2e0..df9fe79058 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -400,110 +400,106 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
TupleTableSlot *outerslot;
TupleTableSlot *scanslot;
- /*
- * This array has to be in the same order as enum ExprEvalOp.
- */
#if defined(EEO_USE_COMPUTED_GOTO)
static const void *const dispatch_table[] = {
- &&CASE_EEOP_DONE,
- &&CASE_EEOP_INNER_FETCHSOME,
- &&CASE_EEOP_OUTER_FETCHSOME,
- &&CASE_EEOP_SCAN_FETCHSOME,
- &&CASE_EEOP_INNER_VAR,
- &&CASE_EEOP_OUTER_VAR,
- &&CASE_EEOP_SCAN_VAR,
- &&CASE_EEOP_INNER_SYSVAR,
- &&CASE_EEOP_OUTER_SYSVAR,
- &&CASE_EEOP_SCAN_SYSVAR,
- &&CASE_EEOP_WHOLEROW,
- &&CASE_EEOP_ASSIGN_INNER_VAR,
- &&CASE_EEOP_ASSIGN_OUTER_VAR,
- &&CASE_EEOP_ASSIGN_SCAN_VAR,
- &&CASE_EEOP_ASSIGN_TMP,
- &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
- &&CASE_EEOP_CONST,
- &&CASE_EEOP_FUNCEXPR,
- &&CASE_EEOP_FUNCEXPR_STRICT,
- &&CASE_EEOP_FUNCEXPR_FUSAGE,
- &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
- &&CASE_EEOP_BOOL_AND_STEP_FIRST,
- &&CASE_EEOP_BOOL_AND_STEP,
- &&CASE_EEOP_BOOL_AND_STEP_LAST,
- &&CASE_EEOP_BOOL_OR_STEP_FIRST,
- &&CASE_EEOP_BOOL_OR_STEP,
- &&CASE_EEOP_BOOL_OR_STEP_LAST,
- &&CASE_EEOP_BOOL_NOT_STEP,
- &&CASE_EEOP_QUAL,
- &&CASE_EEOP_JUMP,
- &&CASE_EEOP_JUMP_IF_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_TRUE,
- &&CASE_EEOP_NULLTEST_ISNULL,
- &&CASE_EEOP_NULLTEST_ISNOTNULL,
- &&CASE_EEOP_NULLTEST_ROWISNULL,
- &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
- &&CASE_EEOP_BOOLTEST_IS_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_FALSE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
- &&CASE_EEOP_PARAM_EXEC,
- &&CASE_EEOP_PARAM_EXTERN,
- &&CASE_EEOP_PARAM_CALLBACK,
- &&CASE_EEOP_CASE_TESTVAL,
- &&CASE_EEOP_MAKE_READONLY,
- &&CASE_EEOP_IOCOERCE,
- &&CASE_EEOP_IOCOERCE_SAFE,
- &&CASE_EEOP_DISTINCT,
- &&CASE_EEOP_NOT_DISTINCT,
- &&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
- &&CASE_EEOP_CURRENTOFEXPR,
- &&CASE_EEOP_NEXTVALUEEXPR,
- &&CASE_EEOP_ARRAYEXPR,
- &&CASE_EEOP_ARRAYCOERCE,
- &&CASE_EEOP_ROW,
- &&CASE_EEOP_ROWCOMPARE_STEP,
- &&CASE_EEOP_ROWCOMPARE_FINAL,
- &&CASE_EEOP_MINMAX,
- &&CASE_EEOP_FIELDSELECT,
- &&CASE_EEOP_FIELDSTORE_DEFORM,
- &&CASE_EEOP_FIELDSTORE_FORM,
- &&CASE_EEOP_SBSREF_SUBSCRIPTS,
- &&CASE_EEOP_SBSREF_OLD,
- &&CASE_EEOP_SBSREF_ASSIGN,
- &&CASE_EEOP_SBSREF_FETCH,
- &&CASE_EEOP_DOMAIN_TESTVAL,
- &&CASE_EEOP_DOMAIN_NOTNULL,
- &&CASE_EEOP_DOMAIN_CHECK,
- &&CASE_EEOP_CONVERT_ROWTYPE,
- &&CASE_EEOP_SCALARARRAYOP,
- &&CASE_EEOP_HASHED_SCALARARRAYOP,
- &&CASE_EEOP_XMLEXPR,
- &&CASE_EEOP_JSON_CONSTRUCTOR,
- &&CASE_EEOP_IS_JSON,
- &&CASE_EEOP_AGGREF,
- &&CASE_EEOP_GROUPING_FUNC,
- &&CASE_EEOP_WINDOW_FUNC,
- &&CASE_EEOP_SUBPLAN,
- &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
- &&CASE_EEOP_AGG_DESERIALIZE,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
- &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
- &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
- &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
- &&CASE_EEOP_LAST
+ [EEOP_DONE] = &&CASE_EEOP_DONE,
+ [EEOP_INNER_FETCHSOME] = &&CASE_EEOP_INNER_FETCHSOME,
+ [EEOP_OUTER_FETCHSOME] = &&CASE_EEOP_OUTER_FETCHSOME,
+ [EEOP_SCAN_FETCHSOME] = &&CASE_EEOP_SCAN_FETCHSOME,
+ [EEOP_INNER_VAR] = &&CASE_EEOP_INNER_VAR,
+ [EEOP_OUTER_VAR] = &&CASE_EEOP_OUTER_VAR,
+ [EEOP_SCAN_VAR] = &&CASE_EEOP_SCAN_VAR,
+ [EEOP_INNER_SYSVAR] = &&CASE_EEOP_INNER_SYSVAR,
+ [EEOP_OUTER_SYSVAR] = &&CASE_EEOP_OUTER_SYSVAR,
+ [EEOP_SCAN_SYSVAR] = &&CASE_EEOP_SCAN_SYSVAR,
+ [EEOP_WHOLEROW] = &&CASE_EEOP_WHOLEROW,
+ [EEOP_ASSIGN_INNER_VAR] = &&CASE_EEOP_ASSIGN_INNER_VAR,
+ [EEOP_ASSIGN_OUTER_VAR] = &&CASE_EEOP_ASSIGN_OUTER_VAR,
+ [EEOP_ASSIGN_SCAN_VAR] = &&CASE_EEOP_ASSIGN_SCAN_VAR,
+ [EEOP_ASSIGN_TMP] = &&CASE_EEOP_ASSIGN_TMP,
+ [EEOP_ASSIGN_TMP_MAKE_RO] = &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
+ [EEOP_CONST] = &&CASE_EEOP_CONST,
+ [EEOP_FUNCEXPR] = &&CASE_EEOP_FUNCEXPR,
+ [EEOP_FUNCEXPR_STRICT] = &&CASE_EEOP_FUNCEXPR_STRICT,
+ [EEOP_FUNCEXPR_FUSAGE] = &&CASE_EEOP_FUNCEXPR_FUSAGE,
+ [EEOP_FUNCEXPR_STRICT_FUSAGE] = &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
+ [EEOP_BOOL_AND_STEP_FIRST] = &&CASE_EEOP_BOOL_AND_STEP_FIRST,
+ [EEOP_BOOL_AND_STEP] = &&CASE_EEOP_BOOL_AND_STEP,
+ [EEOP_BOOL_AND_STEP_LAST] = &&CASE_EEOP_BOOL_AND_STEP_LAST,
+ [EEOP_BOOL_OR_STEP_FIRST] = &&CASE_EEOP_BOOL_OR_STEP_FIRST,
+ [EEOP_BOOL_OR_STEP] = &&CASE_EEOP_BOOL_OR_STEP,
+ [EEOP_BOOL_OR_STEP_LAST] = &&CASE_EEOP_BOOL_OR_STEP_LAST,
+ [EEOP_BOOL_NOT_STEP] = &&CASE_EEOP_BOOL_NOT_STEP,
+ [EEOP_QUAL] = &&CASE_EEOP_QUAL,
+ [EEOP_JUMP] = &&CASE_EEOP_JUMP,
+ [EEOP_JUMP_IF_NULL] = &&CASE_EEOP_JUMP_IF_NULL,
+ [EEOP_JUMP_IF_NOT_NULL] = &&CASE_EEOP_JUMP_IF_NOT_NULL,
+ [EEOP_JUMP_IF_NOT_TRUE] = &&CASE_EEOP_JUMP_IF_NOT_TRUE,
+ [EEOP_NULLTEST_ISNULL] = &&CASE_EEOP_NULLTEST_ISNULL,
+ [EEOP_NULLTEST_ISNOTNULL] = &&CASE_EEOP_NULLTEST_ISNOTNULL,
+ [EEOP_NULLTEST_ROWISNULL] = &&CASE_EEOP_NULLTEST_ROWISNULL,
+ [EEOP_NULLTEST_ROWISNOTNULL] = &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
+ [EEOP_BOOLTEST_IS_TRUE] = &&CASE_EEOP_BOOLTEST_IS_TRUE,
+ [EEOP_BOOLTEST_IS_NOT_TRUE] = &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
+ [EEOP_BOOLTEST_IS_FALSE] = &&CASE_EEOP_BOOLTEST_IS_FALSE,
+ [EEOP_BOOLTEST_IS_NOT_FALSE] = &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
+ [EEOP_PARAM_EXEC] = &&CASE_EEOP_PARAM_EXEC,
+ [EEOP_PARAM_EXTERN] = &&CASE_EEOP_PARAM_EXTERN,
+ [EEOP_PARAM_CALLBACK] = &&CASE_EEOP_PARAM_CALLBACK,
+ [EEOP_CASE_TESTVAL] = &&CASE_EEOP_CASE_TESTVAL,
+ [EEOP_MAKE_READONLY] = &&CASE_EEOP_MAKE_READONLY,
+ [EEOP_IOCOERCE] = &&CASE_EEOP_IOCOERCE,
+ [EEOP_IOCOERCE_SAFE] = &&CASE_EEOP_IOCOERCE_SAFE,
+ [EEOP_DISTINCT] = &&CASE_EEOP_DISTINCT,
+ [EEOP_NOT_DISTINCT] = &&CASE_EEOP_NOT_DISTINCT,
+ [EEOP_NULLIF] = &&CASE_EEOP_NULLIF,
+ [EEOP_SQLVALUEFUNCTION] = &&CASE_EEOP_SQLVALUEFUNCTION,
+ [EEOP_CURRENTOFEXPR] = &&CASE_EEOP_CURRENTOFEXPR,
+ [EEOP_NEXTVALUEEXPR] = &&CASE_EEOP_NEXTVALUEEXPR,
+ [EEOP_ARRAYEXPR] = &&CASE_EEOP_ARRAYEXPR,
+ [EEOP_ARRAYCOERCE] = &&CASE_EEOP_ARRAYCOERCE,
+ [EEOP_ROW] = &&CASE_EEOP_ROW,
+ [EEOP_ROWCOMPARE_STEP] = &&CASE_EEOP_ROWCOMPARE_STEP,
+ [EEOP_ROWCOMPARE_FINAL] = &&CASE_EEOP_ROWCOMPARE_FINAL,
+ [EEOP_MINMAX] = &&CASE_EEOP_MINMAX,
+ [EEOP_FIELDSELECT] = &&CASE_EEOP_FIELDSELECT,
+ [EEOP_FIELDSTORE_DEFORM] = &&CASE_EEOP_FIELDSTORE_DEFORM,
+ [EEOP_FIELDSTORE_FORM] = &&CASE_EEOP_FIELDSTORE_FORM,
+ [EEOP_SBSREF_SUBSCRIPTS] = &&CASE_EEOP_SBSREF_SUBSCRIPTS,
+ [EEOP_SBSREF_OLD] = &&CASE_EEOP_SBSREF_OLD,
+ [EEOP_SBSREF_ASSIGN] = &&CASE_EEOP_SBSREF_ASSIGN,
+ [EEOP_SBSREF_FETCH] = &&CASE_EEOP_SBSREF_FETCH,
+ [EEOP_DOMAIN_TESTVAL] = &&CASE_EEOP_DOMAIN_TESTVAL,
+ [EEOP_DOMAIN_NOTNULL] = &&CASE_EEOP_DOMAIN_NOTNULL,
+ [EEOP_DOMAIN_CHECK] = &&CASE_EEOP_DOMAIN_CHECK,
+ [EEOP_CONVERT_ROWTYPE] = &&CASE_EEOP_CONVERT_ROWTYPE,
+ [EEOP_SCALARARRAYOP] = &&CASE_EEOP_SCALARARRAYOP,
+ [EEOP_HASHED_SCALARARRAYOP] = &&CASE_EEOP_HASHED_SCALARARRAYOP,
+ [EEOP_XMLEXPR] = &&CASE_EEOP_XMLEXPR,
+ [EEOP_JSON_CONSTRUCTOR] = &&CASE_EEOP_JSON_CONSTRUCTOR,
+ [EEOP_IS_JSON] = &&CASE_EEOP_IS_JSON,
+ [EEOP_AGGREF] = &&CASE_EEOP_AGGREF,
+ [EEOP_GROUPING_FUNC] = &&CASE_EEOP_GROUPING_FUNC,
+ [EEOP_WINDOW_FUNC] = &&CASE_EEOP_WINDOW_FUNC,
+ [EEOP_SUBPLAN] = &&CASE_EEOP_SUBPLAN,
+ [EEOP_AGG_STRICT_DESERIALIZE] = &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
+ [EEOP_AGG_DESERIALIZE] = &&CASE_EEOP_AGG_DESERIALIZE,
+ [EEOP_AGG_STRICT_INPUT_CHECK_ARGS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
+ [EEOP_AGG_STRICT_INPUT_CHECK_NULLS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
+ [EEOP_AGG_PLAIN_PERGROUP_NULLCHECK] = &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
+ [EEOP_AGG_PRESORTED_DISTINCT_SINGLE] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
+ [EEOP_AGG_PRESORTED_DISTINCT_MULTI] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
+ [EEOP_AGG_ORDERED_TRANS_DATUM] = &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
+ [EEOP_AGG_ORDERED_TRANS_TUPLE] = &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
};
- StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
+ StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST,
"dispatch_table out of whack with ExprEvalOp");
if (unlikely(state == NULL))
@@ -1845,13 +1841,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
-
- EEO_CASE(EEOP_LAST)
- {
- /* unreachable */
- Assert(false);
- goto out;
- }
}
out:
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index a28ddcdd77..00d3db7a74 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -60,7 +60,7 @@ typedef struct ExprEvalRowtypeCache
* Identifies the operation to be executed and which member in the
* ExprEvalStep->d union is valid.
*
- * The order of entries needs to be kept in sync with the dispatch_table[]
+ * If you add some operation don't forget to update the dispatch_table[]
* array in execExprInterp.c:ExecInterpExpr().
*/
typedef enum ExprEvalOp
--
2.34.1
--=-=-=--
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v2 1/1] Use C99-designated initializer syntax for dispatch_table array
@ 2024-03-05 13:32 Japin Li <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Japin Li @ 2024-03-05 13:32 UTC (permalink / raw)
---
src/backend/executor/execExprInterp.c | 195 +++++++++++++-------------
src/include/executor/execExpr.h | 2 +-
2 files changed, 97 insertions(+), 100 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 7c1f51e2e0..e4ad522312 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -400,107 +400,104 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
TupleTableSlot *outerslot;
TupleTableSlot *scanslot;
- /*
- * This array has to be in the same order as enum ExprEvalOp.
- */
#if defined(EEO_USE_COMPUTED_GOTO)
static const void *const dispatch_table[] = {
- &&CASE_EEOP_DONE,
- &&CASE_EEOP_INNER_FETCHSOME,
- &&CASE_EEOP_OUTER_FETCHSOME,
- &&CASE_EEOP_SCAN_FETCHSOME,
- &&CASE_EEOP_INNER_VAR,
- &&CASE_EEOP_OUTER_VAR,
- &&CASE_EEOP_SCAN_VAR,
- &&CASE_EEOP_INNER_SYSVAR,
- &&CASE_EEOP_OUTER_SYSVAR,
- &&CASE_EEOP_SCAN_SYSVAR,
- &&CASE_EEOP_WHOLEROW,
- &&CASE_EEOP_ASSIGN_INNER_VAR,
- &&CASE_EEOP_ASSIGN_OUTER_VAR,
- &&CASE_EEOP_ASSIGN_SCAN_VAR,
- &&CASE_EEOP_ASSIGN_TMP,
- &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
- &&CASE_EEOP_CONST,
- &&CASE_EEOP_FUNCEXPR,
- &&CASE_EEOP_FUNCEXPR_STRICT,
- &&CASE_EEOP_FUNCEXPR_FUSAGE,
- &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
- &&CASE_EEOP_BOOL_AND_STEP_FIRST,
- &&CASE_EEOP_BOOL_AND_STEP,
- &&CASE_EEOP_BOOL_AND_STEP_LAST,
- &&CASE_EEOP_BOOL_OR_STEP_FIRST,
- &&CASE_EEOP_BOOL_OR_STEP,
- &&CASE_EEOP_BOOL_OR_STEP_LAST,
- &&CASE_EEOP_BOOL_NOT_STEP,
- &&CASE_EEOP_QUAL,
- &&CASE_EEOP_JUMP,
- &&CASE_EEOP_JUMP_IF_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_TRUE,
- &&CASE_EEOP_NULLTEST_ISNULL,
- &&CASE_EEOP_NULLTEST_ISNOTNULL,
- &&CASE_EEOP_NULLTEST_ROWISNULL,
- &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
- &&CASE_EEOP_BOOLTEST_IS_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_FALSE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
- &&CASE_EEOP_PARAM_EXEC,
- &&CASE_EEOP_PARAM_EXTERN,
- &&CASE_EEOP_PARAM_CALLBACK,
- &&CASE_EEOP_CASE_TESTVAL,
- &&CASE_EEOP_MAKE_READONLY,
- &&CASE_EEOP_IOCOERCE,
- &&CASE_EEOP_IOCOERCE_SAFE,
- &&CASE_EEOP_DISTINCT,
- &&CASE_EEOP_NOT_DISTINCT,
- &&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
- &&CASE_EEOP_CURRENTOFEXPR,
- &&CASE_EEOP_NEXTVALUEEXPR,
- &&CASE_EEOP_ARRAYEXPR,
- &&CASE_EEOP_ARRAYCOERCE,
- &&CASE_EEOP_ROW,
- &&CASE_EEOP_ROWCOMPARE_STEP,
- &&CASE_EEOP_ROWCOMPARE_FINAL,
- &&CASE_EEOP_MINMAX,
- &&CASE_EEOP_FIELDSELECT,
- &&CASE_EEOP_FIELDSTORE_DEFORM,
- &&CASE_EEOP_FIELDSTORE_FORM,
- &&CASE_EEOP_SBSREF_SUBSCRIPTS,
- &&CASE_EEOP_SBSREF_OLD,
- &&CASE_EEOP_SBSREF_ASSIGN,
- &&CASE_EEOP_SBSREF_FETCH,
- &&CASE_EEOP_DOMAIN_TESTVAL,
- &&CASE_EEOP_DOMAIN_NOTNULL,
- &&CASE_EEOP_DOMAIN_CHECK,
- &&CASE_EEOP_CONVERT_ROWTYPE,
- &&CASE_EEOP_SCALARARRAYOP,
- &&CASE_EEOP_HASHED_SCALARARRAYOP,
- &&CASE_EEOP_XMLEXPR,
- &&CASE_EEOP_JSON_CONSTRUCTOR,
- &&CASE_EEOP_IS_JSON,
- &&CASE_EEOP_AGGREF,
- &&CASE_EEOP_GROUPING_FUNC,
- &&CASE_EEOP_WINDOW_FUNC,
- &&CASE_EEOP_SUBPLAN,
- &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
- &&CASE_EEOP_AGG_DESERIALIZE,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
- &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
- &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
- &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
- &&CASE_EEOP_LAST
+ [EEOP_DONE] = &&CASE_EEOP_DONE,
+ [EEOP_INNER_FETCHSOME] = &&CASE_EEOP_INNER_FETCHSOME,
+ [EEOP_OUTER_FETCHSOME] = &&CASE_EEOP_OUTER_FETCHSOME,
+ [EEOP_SCAN_FETCHSOME] = &&CASE_EEOP_SCAN_FETCHSOME,
+ [EEOP_INNER_VAR] = &&CASE_EEOP_INNER_VAR,
+ [EEOP_OUTER_VAR] = &&CASE_EEOP_OUTER_VAR,
+ [EEOP_SCAN_VAR] = &&CASE_EEOP_SCAN_VAR,
+ [EEOP_INNER_SYSVAR] = &&CASE_EEOP_INNER_SYSVAR,
+ [EEOP_OUTER_SYSVAR] = &&CASE_EEOP_OUTER_SYSVAR,
+ [EEOP_SCAN_SYSVAR] = &&CASE_EEOP_SCAN_SYSVAR,
+ [EEOP_WHOLEROW] = &&CASE_EEOP_WHOLEROW,
+ [EEOP_ASSIGN_INNER_VAR] = &&CASE_EEOP_ASSIGN_INNER_VAR,
+ [EEOP_ASSIGN_OUTER_VAR] = &&CASE_EEOP_ASSIGN_OUTER_VAR,
+ [EEOP_ASSIGN_SCAN_VAR] = &&CASE_EEOP_ASSIGN_SCAN_VAR,
+ [EEOP_ASSIGN_TMP] = &&CASE_EEOP_ASSIGN_TMP,
+ [EEOP_ASSIGN_TMP_MAKE_RO] = &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
+ [EEOP_CONST] = &&CASE_EEOP_CONST,
+ [EEOP_FUNCEXPR] = &&CASE_EEOP_FUNCEXPR,
+ [EEOP_FUNCEXPR_STRICT] = &&CASE_EEOP_FUNCEXPR_STRICT,
+ [EEOP_FUNCEXPR_FUSAGE] = &&CASE_EEOP_FUNCEXPR_FUSAGE,
+ [EEOP_FUNCEXPR_STRICT_FUSAGE] = &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
+ [EEOP_BOOL_AND_STEP_FIRST] = &&CASE_EEOP_BOOL_AND_STEP_FIRST,
+ [EEOP_BOOL_AND_STEP] = &&CASE_EEOP_BOOL_AND_STEP,
+ [EEOP_BOOL_AND_STEP_LAST] = &&CASE_EEOP_BOOL_AND_STEP_LAST,
+ [EEOP_BOOL_OR_STEP_FIRST] = &&CASE_EEOP_BOOL_OR_STEP_FIRST,
+ [EEOP_BOOL_OR_STEP] = &&CASE_EEOP_BOOL_OR_STEP,
+ [EEOP_BOOL_OR_STEP_LAST] = &&CASE_EEOP_BOOL_OR_STEP_LAST,
+ [EEOP_BOOL_NOT_STEP] = &&CASE_EEOP_BOOL_NOT_STEP,
+ [EEOP_QUAL] = &&CASE_EEOP_QUAL,
+ [EEOP_JUMP] = &&CASE_EEOP_JUMP,
+ [EEOP_JUMP_IF_NULL] = &&CASE_EEOP_JUMP_IF_NULL,
+ [EEOP_JUMP_IF_NOT_NULL] = &&CASE_EEOP_JUMP_IF_NOT_NULL,
+ [EEOP_JUMP_IF_NOT_TRUE] = &&CASE_EEOP_JUMP_IF_NOT_TRUE,
+ [EEOP_NULLTEST_ISNULL] = &&CASE_EEOP_NULLTEST_ISNULL,
+ [EEOP_NULLTEST_ISNOTNULL] = &&CASE_EEOP_NULLTEST_ISNOTNULL,
+ [EEOP_NULLTEST_ROWISNULL] = &&CASE_EEOP_NULLTEST_ROWISNULL,
+ [EEOP_NULLTEST_ROWISNOTNULL] = &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
+ [EEOP_BOOLTEST_IS_TRUE] = &&CASE_EEOP_BOOLTEST_IS_TRUE,
+ [EEOP_BOOLTEST_IS_NOT_TRUE] = &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
+ [EEOP_BOOLTEST_IS_FALSE] = &&CASE_EEOP_BOOLTEST_IS_FALSE,
+ [EEOP_BOOLTEST_IS_NOT_FALSE] = &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
+ [EEOP_PARAM_EXEC] = &&CASE_EEOP_PARAM_EXEC,
+ [EEOP_PARAM_EXTERN] = &&CASE_EEOP_PARAM_EXTERN,
+ [EEOP_PARAM_CALLBACK] = &&CASE_EEOP_PARAM_CALLBACK,
+ [EEOP_CASE_TESTVAL] = &&CASE_EEOP_CASE_TESTVAL,
+ [EEOP_MAKE_READONLY] = &&CASE_EEOP_MAKE_READONLY,
+ [EEOP_IOCOERCE] = &&CASE_EEOP_IOCOERCE,
+ [EEOP_IOCOERCE_SAFE] = &&CASE_EEOP_IOCOERCE_SAFE,
+ [EEOP_DISTINCT] = &&CASE_EEOP_DISTINCT,
+ [EEOP_NOT_DISTINCT] = &&CASE_EEOP_NOT_DISTINCT,
+ [EEOP_NULLIF] = &&CASE_EEOP_NULLIF,
+ [EEOP_SQLVALUEFUNCTION] = &&CASE_EEOP_SQLVALUEFUNCTION,
+ [EEOP_CURRENTOFEXPR] = &&CASE_EEOP_CURRENTOFEXPR,
+ [EEOP_NEXTVALUEEXPR] = &&CASE_EEOP_NEXTVALUEEXPR,
+ [EEOP_ARRAYEXPR] = &&CASE_EEOP_ARRAYEXPR,
+ [EEOP_ARRAYCOERCE] = &&CASE_EEOP_ARRAYCOERCE,
+ [EEOP_ROW] = &&CASE_EEOP_ROW,
+ [EEOP_ROWCOMPARE_STEP] = &&CASE_EEOP_ROWCOMPARE_STEP,
+ [EEOP_ROWCOMPARE_FINAL] = &&CASE_EEOP_ROWCOMPARE_FINAL,
+ [EEOP_MINMAX] = &&CASE_EEOP_MINMAX,
+ [EEOP_FIELDSELECT] = &&CASE_EEOP_FIELDSELECT,
+ [EEOP_FIELDSTORE_DEFORM] = &&CASE_EEOP_FIELDSTORE_DEFORM,
+ [EEOP_FIELDSTORE_FORM] = &&CASE_EEOP_FIELDSTORE_FORM,
+ [EEOP_SBSREF_SUBSCRIPTS] = &&CASE_EEOP_SBSREF_SUBSCRIPTS,
+ [EEOP_SBSREF_OLD] = &&CASE_EEOP_SBSREF_OLD,
+ [EEOP_SBSREF_ASSIGN] = &&CASE_EEOP_SBSREF_ASSIGN,
+ [EEOP_SBSREF_FETCH] = &&CASE_EEOP_SBSREF_FETCH,
+ [EEOP_DOMAIN_TESTVAL] = &&CASE_EEOP_DOMAIN_TESTVAL,
+ [EEOP_DOMAIN_NOTNULL] = &&CASE_EEOP_DOMAIN_NOTNULL,
+ [EEOP_DOMAIN_CHECK] = &&CASE_EEOP_DOMAIN_CHECK,
+ [EEOP_CONVERT_ROWTYPE] = &&CASE_EEOP_CONVERT_ROWTYPE,
+ [EEOP_SCALARARRAYOP] = &&CASE_EEOP_SCALARARRAYOP,
+ [EEOP_HASHED_SCALARARRAYOP] = &&CASE_EEOP_HASHED_SCALARARRAYOP,
+ [EEOP_XMLEXPR] = &&CASE_EEOP_XMLEXPR,
+ [EEOP_JSON_CONSTRUCTOR] = &&CASE_EEOP_JSON_CONSTRUCTOR,
+ [EEOP_IS_JSON] = &&CASE_EEOP_IS_JSON,
+ [EEOP_AGGREF] = &&CASE_EEOP_AGGREF,
+ [EEOP_GROUPING_FUNC] = &&CASE_EEOP_GROUPING_FUNC,
+ [EEOP_WINDOW_FUNC] = &&CASE_EEOP_WINDOW_FUNC,
+ [EEOP_SUBPLAN] = &&CASE_EEOP_SUBPLAN,
+ [EEOP_AGG_STRICT_DESERIALIZE] = &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
+ [EEOP_AGG_DESERIALIZE] = &&CASE_EEOP_AGG_DESERIALIZE,
+ [EEOP_AGG_STRICT_INPUT_CHECK_ARGS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
+ [EEOP_AGG_STRICT_INPUT_CHECK_NULLS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
+ [EEOP_AGG_PLAIN_PERGROUP_NULLCHECK] = &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
+ [EEOP_AGG_PRESORTED_DISTINCT_SINGLE] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
+ [EEOP_AGG_PRESORTED_DISTINCT_MULTI] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
+ [EEOP_AGG_ORDERED_TRANS_DATUM] = &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
+ [EEOP_AGG_ORDERED_TRANS_TUPLE] = &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
+ [EEOP_LAST] = &&CASE_EEOP_LAST,
};
StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index a28ddcdd77..00d3db7a74 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -60,7 +60,7 @@ typedef struct ExprEvalRowtypeCache
* Identifies the operation to be executed and which member in the
* ExprEvalStep->d union is valid.
*
- * The order of entries needs to be kept in sync with the dispatch_table[]
+ * If you add some operation don't forget to update the dispatch_table[]
* array in execExprInterp.c:ExecInterpExpr().
*/
typedef enum ExprEvalOp
--
2.34.1
--=-=-=--
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/1] Use C99-designated initializer syntax for dispatch_table array
@ 2024-03-05 13:32 Japin Li <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Japin Li @ 2024-03-05 13:32 UTC (permalink / raw)
---
src/backend/executor/execExprInterp.c | 195 +++++++++++++-------------
src/include/executor/execExpr.h | 3 -
2 files changed, 96 insertions(+), 102 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 7c1f51e2e0..e4ad522312 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -400,107 +400,104 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
TupleTableSlot *outerslot;
TupleTableSlot *scanslot;
- /*
- * This array has to be in the same order as enum ExprEvalOp.
- */
#if defined(EEO_USE_COMPUTED_GOTO)
static const void *const dispatch_table[] = {
- &&CASE_EEOP_DONE,
- &&CASE_EEOP_INNER_FETCHSOME,
- &&CASE_EEOP_OUTER_FETCHSOME,
- &&CASE_EEOP_SCAN_FETCHSOME,
- &&CASE_EEOP_INNER_VAR,
- &&CASE_EEOP_OUTER_VAR,
- &&CASE_EEOP_SCAN_VAR,
- &&CASE_EEOP_INNER_SYSVAR,
- &&CASE_EEOP_OUTER_SYSVAR,
- &&CASE_EEOP_SCAN_SYSVAR,
- &&CASE_EEOP_WHOLEROW,
- &&CASE_EEOP_ASSIGN_INNER_VAR,
- &&CASE_EEOP_ASSIGN_OUTER_VAR,
- &&CASE_EEOP_ASSIGN_SCAN_VAR,
- &&CASE_EEOP_ASSIGN_TMP,
- &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
- &&CASE_EEOP_CONST,
- &&CASE_EEOP_FUNCEXPR,
- &&CASE_EEOP_FUNCEXPR_STRICT,
- &&CASE_EEOP_FUNCEXPR_FUSAGE,
- &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
- &&CASE_EEOP_BOOL_AND_STEP_FIRST,
- &&CASE_EEOP_BOOL_AND_STEP,
- &&CASE_EEOP_BOOL_AND_STEP_LAST,
- &&CASE_EEOP_BOOL_OR_STEP_FIRST,
- &&CASE_EEOP_BOOL_OR_STEP,
- &&CASE_EEOP_BOOL_OR_STEP_LAST,
- &&CASE_EEOP_BOOL_NOT_STEP,
- &&CASE_EEOP_QUAL,
- &&CASE_EEOP_JUMP,
- &&CASE_EEOP_JUMP_IF_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_NULL,
- &&CASE_EEOP_JUMP_IF_NOT_TRUE,
- &&CASE_EEOP_NULLTEST_ISNULL,
- &&CASE_EEOP_NULLTEST_ISNOTNULL,
- &&CASE_EEOP_NULLTEST_ROWISNULL,
- &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
- &&CASE_EEOP_BOOLTEST_IS_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
- &&CASE_EEOP_BOOLTEST_IS_FALSE,
- &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
- &&CASE_EEOP_PARAM_EXEC,
- &&CASE_EEOP_PARAM_EXTERN,
- &&CASE_EEOP_PARAM_CALLBACK,
- &&CASE_EEOP_CASE_TESTVAL,
- &&CASE_EEOP_MAKE_READONLY,
- &&CASE_EEOP_IOCOERCE,
- &&CASE_EEOP_IOCOERCE_SAFE,
- &&CASE_EEOP_DISTINCT,
- &&CASE_EEOP_NOT_DISTINCT,
- &&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
- &&CASE_EEOP_CURRENTOFEXPR,
- &&CASE_EEOP_NEXTVALUEEXPR,
- &&CASE_EEOP_ARRAYEXPR,
- &&CASE_EEOP_ARRAYCOERCE,
- &&CASE_EEOP_ROW,
- &&CASE_EEOP_ROWCOMPARE_STEP,
- &&CASE_EEOP_ROWCOMPARE_FINAL,
- &&CASE_EEOP_MINMAX,
- &&CASE_EEOP_FIELDSELECT,
- &&CASE_EEOP_FIELDSTORE_DEFORM,
- &&CASE_EEOP_FIELDSTORE_FORM,
- &&CASE_EEOP_SBSREF_SUBSCRIPTS,
- &&CASE_EEOP_SBSREF_OLD,
- &&CASE_EEOP_SBSREF_ASSIGN,
- &&CASE_EEOP_SBSREF_FETCH,
- &&CASE_EEOP_DOMAIN_TESTVAL,
- &&CASE_EEOP_DOMAIN_NOTNULL,
- &&CASE_EEOP_DOMAIN_CHECK,
- &&CASE_EEOP_CONVERT_ROWTYPE,
- &&CASE_EEOP_SCALARARRAYOP,
- &&CASE_EEOP_HASHED_SCALARARRAYOP,
- &&CASE_EEOP_XMLEXPR,
- &&CASE_EEOP_JSON_CONSTRUCTOR,
- &&CASE_EEOP_IS_JSON,
- &&CASE_EEOP_AGGREF,
- &&CASE_EEOP_GROUPING_FUNC,
- &&CASE_EEOP_WINDOW_FUNC,
- &&CASE_EEOP_SUBPLAN,
- &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
- &&CASE_EEOP_AGG_DESERIALIZE,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
- &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
- &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
- &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
- &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
- &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
- &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
- &&CASE_EEOP_LAST
+ [EEOP_DONE] = &&CASE_EEOP_DONE,
+ [EEOP_INNER_FETCHSOME] = &&CASE_EEOP_INNER_FETCHSOME,
+ [EEOP_OUTER_FETCHSOME] = &&CASE_EEOP_OUTER_FETCHSOME,
+ [EEOP_SCAN_FETCHSOME] = &&CASE_EEOP_SCAN_FETCHSOME,
+ [EEOP_INNER_VAR] = &&CASE_EEOP_INNER_VAR,
+ [EEOP_OUTER_VAR] = &&CASE_EEOP_OUTER_VAR,
+ [EEOP_SCAN_VAR] = &&CASE_EEOP_SCAN_VAR,
+ [EEOP_INNER_SYSVAR] = &&CASE_EEOP_INNER_SYSVAR,
+ [EEOP_OUTER_SYSVAR] = &&CASE_EEOP_OUTER_SYSVAR,
+ [EEOP_SCAN_SYSVAR] = &&CASE_EEOP_SCAN_SYSVAR,
+ [EEOP_WHOLEROW] = &&CASE_EEOP_WHOLEROW,
+ [EEOP_ASSIGN_INNER_VAR] = &&CASE_EEOP_ASSIGN_INNER_VAR,
+ [EEOP_ASSIGN_OUTER_VAR] = &&CASE_EEOP_ASSIGN_OUTER_VAR,
+ [EEOP_ASSIGN_SCAN_VAR] = &&CASE_EEOP_ASSIGN_SCAN_VAR,
+ [EEOP_ASSIGN_TMP] = &&CASE_EEOP_ASSIGN_TMP,
+ [EEOP_ASSIGN_TMP_MAKE_RO] = &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
+ [EEOP_CONST] = &&CASE_EEOP_CONST,
+ [EEOP_FUNCEXPR] = &&CASE_EEOP_FUNCEXPR,
+ [EEOP_FUNCEXPR_STRICT] = &&CASE_EEOP_FUNCEXPR_STRICT,
+ [EEOP_FUNCEXPR_FUSAGE] = &&CASE_EEOP_FUNCEXPR_FUSAGE,
+ [EEOP_FUNCEXPR_STRICT_FUSAGE] = &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
+ [EEOP_BOOL_AND_STEP_FIRST] = &&CASE_EEOP_BOOL_AND_STEP_FIRST,
+ [EEOP_BOOL_AND_STEP] = &&CASE_EEOP_BOOL_AND_STEP,
+ [EEOP_BOOL_AND_STEP_LAST] = &&CASE_EEOP_BOOL_AND_STEP_LAST,
+ [EEOP_BOOL_OR_STEP_FIRST] = &&CASE_EEOP_BOOL_OR_STEP_FIRST,
+ [EEOP_BOOL_OR_STEP] = &&CASE_EEOP_BOOL_OR_STEP,
+ [EEOP_BOOL_OR_STEP_LAST] = &&CASE_EEOP_BOOL_OR_STEP_LAST,
+ [EEOP_BOOL_NOT_STEP] = &&CASE_EEOP_BOOL_NOT_STEP,
+ [EEOP_QUAL] = &&CASE_EEOP_QUAL,
+ [EEOP_JUMP] = &&CASE_EEOP_JUMP,
+ [EEOP_JUMP_IF_NULL] = &&CASE_EEOP_JUMP_IF_NULL,
+ [EEOP_JUMP_IF_NOT_NULL] = &&CASE_EEOP_JUMP_IF_NOT_NULL,
+ [EEOP_JUMP_IF_NOT_TRUE] = &&CASE_EEOP_JUMP_IF_NOT_TRUE,
+ [EEOP_NULLTEST_ISNULL] = &&CASE_EEOP_NULLTEST_ISNULL,
+ [EEOP_NULLTEST_ISNOTNULL] = &&CASE_EEOP_NULLTEST_ISNOTNULL,
+ [EEOP_NULLTEST_ROWISNULL] = &&CASE_EEOP_NULLTEST_ROWISNULL,
+ [EEOP_NULLTEST_ROWISNOTNULL] = &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
+ [EEOP_BOOLTEST_IS_TRUE] = &&CASE_EEOP_BOOLTEST_IS_TRUE,
+ [EEOP_BOOLTEST_IS_NOT_TRUE] = &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
+ [EEOP_BOOLTEST_IS_FALSE] = &&CASE_EEOP_BOOLTEST_IS_FALSE,
+ [EEOP_BOOLTEST_IS_NOT_FALSE] = &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
+ [EEOP_PARAM_EXEC] = &&CASE_EEOP_PARAM_EXEC,
+ [EEOP_PARAM_EXTERN] = &&CASE_EEOP_PARAM_EXTERN,
+ [EEOP_PARAM_CALLBACK] = &&CASE_EEOP_PARAM_CALLBACK,
+ [EEOP_CASE_TESTVAL] = &&CASE_EEOP_CASE_TESTVAL,
+ [EEOP_MAKE_READONLY] = &&CASE_EEOP_MAKE_READONLY,
+ [EEOP_IOCOERCE] = &&CASE_EEOP_IOCOERCE,
+ [EEOP_IOCOERCE_SAFE] = &&CASE_EEOP_IOCOERCE_SAFE,
+ [EEOP_DISTINCT] = &&CASE_EEOP_DISTINCT,
+ [EEOP_NOT_DISTINCT] = &&CASE_EEOP_NOT_DISTINCT,
+ [EEOP_NULLIF] = &&CASE_EEOP_NULLIF,
+ [EEOP_SQLVALUEFUNCTION] = &&CASE_EEOP_SQLVALUEFUNCTION,
+ [EEOP_CURRENTOFEXPR] = &&CASE_EEOP_CURRENTOFEXPR,
+ [EEOP_NEXTVALUEEXPR] = &&CASE_EEOP_NEXTVALUEEXPR,
+ [EEOP_ARRAYEXPR] = &&CASE_EEOP_ARRAYEXPR,
+ [EEOP_ARRAYCOERCE] = &&CASE_EEOP_ARRAYCOERCE,
+ [EEOP_ROW] = &&CASE_EEOP_ROW,
+ [EEOP_ROWCOMPARE_STEP] = &&CASE_EEOP_ROWCOMPARE_STEP,
+ [EEOP_ROWCOMPARE_FINAL] = &&CASE_EEOP_ROWCOMPARE_FINAL,
+ [EEOP_MINMAX] = &&CASE_EEOP_MINMAX,
+ [EEOP_FIELDSELECT] = &&CASE_EEOP_FIELDSELECT,
+ [EEOP_FIELDSTORE_DEFORM] = &&CASE_EEOP_FIELDSTORE_DEFORM,
+ [EEOP_FIELDSTORE_FORM] = &&CASE_EEOP_FIELDSTORE_FORM,
+ [EEOP_SBSREF_SUBSCRIPTS] = &&CASE_EEOP_SBSREF_SUBSCRIPTS,
+ [EEOP_SBSREF_OLD] = &&CASE_EEOP_SBSREF_OLD,
+ [EEOP_SBSREF_ASSIGN] = &&CASE_EEOP_SBSREF_ASSIGN,
+ [EEOP_SBSREF_FETCH] = &&CASE_EEOP_SBSREF_FETCH,
+ [EEOP_DOMAIN_TESTVAL] = &&CASE_EEOP_DOMAIN_TESTVAL,
+ [EEOP_DOMAIN_NOTNULL] = &&CASE_EEOP_DOMAIN_NOTNULL,
+ [EEOP_DOMAIN_CHECK] = &&CASE_EEOP_DOMAIN_CHECK,
+ [EEOP_CONVERT_ROWTYPE] = &&CASE_EEOP_CONVERT_ROWTYPE,
+ [EEOP_SCALARARRAYOP] = &&CASE_EEOP_SCALARARRAYOP,
+ [EEOP_HASHED_SCALARARRAYOP] = &&CASE_EEOP_HASHED_SCALARARRAYOP,
+ [EEOP_XMLEXPR] = &&CASE_EEOP_XMLEXPR,
+ [EEOP_JSON_CONSTRUCTOR] = &&CASE_EEOP_JSON_CONSTRUCTOR,
+ [EEOP_IS_JSON] = &&CASE_EEOP_IS_JSON,
+ [EEOP_AGGREF] = &&CASE_EEOP_AGGREF,
+ [EEOP_GROUPING_FUNC] = &&CASE_EEOP_GROUPING_FUNC,
+ [EEOP_WINDOW_FUNC] = &&CASE_EEOP_WINDOW_FUNC,
+ [EEOP_SUBPLAN] = &&CASE_EEOP_SUBPLAN,
+ [EEOP_AGG_STRICT_DESERIALIZE] = &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
+ [EEOP_AGG_DESERIALIZE] = &&CASE_EEOP_AGG_DESERIALIZE,
+ [EEOP_AGG_STRICT_INPUT_CHECK_ARGS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
+ [EEOP_AGG_STRICT_INPUT_CHECK_NULLS] = &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
+ [EEOP_AGG_PLAIN_PERGROUP_NULLCHECK] = &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_BYVAL] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
+ [EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_STRICT_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
+ [EEOP_AGG_PLAIN_TRANS_BYREF] = &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
+ [EEOP_AGG_PRESORTED_DISTINCT_SINGLE] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
+ [EEOP_AGG_PRESORTED_DISTINCT_MULTI] = &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
+ [EEOP_AGG_ORDERED_TRANS_DATUM] = &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
+ [EEOP_AGG_ORDERED_TRANS_TUPLE] = &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
+ [EEOP_LAST] = &&CASE_EEOP_LAST,
};
StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index a28ddcdd77..0a2f389ed7 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -59,9 +59,6 @@ typedef struct ExprEvalRowtypeCache
*
* Identifies the operation to be executed and which member in the
* ExprEvalStep->d union is valid.
- *
- * The order of entries needs to be kept in sync with the dispatch_table[]
- * array in execExprInterp.c:ExecInterpExpr().
*/
typedef enum ExprEvalOp
{
--
2.34.1
--=-=-=--
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
* [PATCH v1 1/4] autovac: save all relopts instead of just avopts
@ 2025-06-23 19:07 Nathan Bossart <[email protected]>
0 siblings, 0 replies; 802+ messages in thread
From: Nathan Bossart @ 2025-06-23 19:07 UTC (permalink / raw)
---
src/backend/postmaster/autovacuum.c | 119 ++++++++++------------------
1 file changed, 43 insertions(+), 76 deletions(-)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 451fb90a610..f86c9fed853 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -192,8 +192,8 @@ typedef struct av_relation
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
- AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
- * reloptions, or NULL if none */
+ StdRdOptions ar_reloptions; /* copy of main table's reloptions, or NULL if
+ * none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
@@ -333,11 +333,11 @@ static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
-static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts,
+static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum, bool *doanalyze, bool *wraparound);
-static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
+static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -345,8 +345,6 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
-static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
- TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
@@ -1995,7 +1993,7 @@ do_autovacuum(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@@ -2033,7 +2031,7 @@ do_autovacuum(void)
}
/* Fetch reloptions and the pgstat entry for this table */
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
@@ -2069,7 +2067,7 @@ do_autovacuum(void)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
- sizeof(AutoVacOpts));
+ sizeof(StdRdOptions));
}
}
}
@@ -2095,7 +2093,7 @@ do_autovacuum(void)
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
- AutoVacOpts *relopts;
+ StdRdOptions *relopts;
bool free_relopts = false;
bool dovacuum;
bool doanalyze;
@@ -2113,7 +2111,7 @@ do_autovacuum(void)
* fetch reloptions -- if this toast table does not have them, try the
* main rel
*/
- relopts = extract_autovac_opts(tuple, pg_class_desc);
+ relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL);
if (relopts)
free_relopts = true;
else
@@ -2701,39 +2699,6 @@ deleted2:
pfree(cur_relname);
}
-/*
- * extract_autovac_opts
- *
- * Given a relation's pg_class tuple, return a palloc'd copy of the
- * AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
- *
- * Note: callers do not have a relation lock on the table at this point,
- * so the table could have been dropped, and its catalog rows gone, after
- * we acquired the pg_class row. If pg_class had a TOAST table, this would
- * be a risk; fortunately, it doesn't.
- */
-static AutoVacOpts *
-extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
-{
- bytea *relopts;
- AutoVacOpts *av;
-
- Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
-
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
-
- av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
-
- return av;
-}
-
-
/*
* table_recheck_autovac
*
@@ -2753,8 +2718,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool doanalyze;
autovac_table *tab = NULL;
bool wraparound;
- AutoVacOpts *avopts;
- bool free_avopts = false;
+ StdRdOptions *relopts;
+ bool free_relopts = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2766,9 +2731,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
- avopts = extract_autovac_opts(classTup, pg_class_desc);
- if (avopts)
- free_avopts = true;
+ relopts = (StdRdOptions *) extractRelOptions(classTup, pg_class_desc, NULL);
+ if (relopts)
+ free_relopts = true;
else if (classForm->relkind == RELKIND_TOASTVALUE &&
table_toast_map != NULL)
{
@@ -2777,10 +2742,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
- avopts = &hentry->ar_reloptions;
+ relopts = &hentry->ar_reloptions;
}
- recheck_relation_needs_vacanalyze(relid, avopts, classForm,
+ recheck_relation_needs_vacanalyze(relid, relopts, classForm,
effective_multixact_freeze_max_age,
&dovacuum, &doanalyze, &wraparound);
@@ -2792,6 +2757,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int log_min_duration;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/*
* Calculate the vacuum cost parameters and the freeze ages. If there
@@ -2879,8 +2845,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts->vacuum_cost_delay >= 0));
}
- if (free_avopts)
- pfree(avopts);
+ if (free_relopts)
+ pfree(relopts);
heap_freetuple(classTup);
return tab;
}
@@ -2895,7 +2861,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
*/
static void
recheck_relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *avopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
int effective_multixact_freeze_max_age,
bool *dovacuum,
@@ -2908,7 +2874,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
relid);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
effective_multixact_freeze_max_age,
dovacuum, doanalyze, wraparound);
@@ -2928,7 +2894,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid or multixact wraparound.
*
- * relopts is a pointer to the AutoVacOpts options (either for itself in the
+ * relopts is a pointer to the StdRdOptions options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
@@ -2962,7 +2928,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
*/
static void
relation_needs_vacanalyze(Oid relid,
- AutoVacOpts *relopts,
+ StdRdOptions *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
int effective_multixact_freeze_max_age,
@@ -2973,6 +2939,7 @@ relation_needs_vacanalyze(Oid relid,
{
bool force_vacuum;
bool av_enabled;
+ AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL);
/* constants from reloptions or GUC variables */
int vac_base_thresh,
@@ -3010,45 +2977,45 @@ relation_needs_vacanalyze(Oid relid,
*/
/* -1 in autovac setting means use plain vacuum_scale_factor */
- vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
- ? relopts->vacuum_scale_factor
+ vac_scale_factor = (avopts && avopts->vacuum_scale_factor >= 0)
+ ? avopts->vacuum_scale_factor
: autovacuum_vac_scale;
- vac_base_thresh = (relopts && relopts->vacuum_threshold >= 0)
- ? relopts->vacuum_threshold
+ vac_base_thresh = (avopts && avopts->vacuum_threshold >= 0)
+ ? avopts->vacuum_threshold
: autovacuum_vac_thresh;
/* -1 is used to disable max threshold */
- vac_max_thresh = (relopts && relopts->vacuum_max_threshold >= -1)
- ? relopts->vacuum_max_threshold
+ vac_max_thresh = (avopts && avopts->vacuum_max_threshold >= -1)
+ ? avopts->vacuum_max_threshold
: autovacuum_vac_max_thresh;
- vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0)
- ? relopts->vacuum_ins_scale_factor
+ vac_ins_scale_factor = (avopts && avopts->vacuum_ins_scale_factor >= 0)
+ ? avopts->vacuum_ins_scale_factor
: autovacuum_vac_ins_scale;
/* -1 is used to disable insert vacuums */
- vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
- ? relopts->vacuum_ins_threshold
+ vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1)
+ ? avopts->vacuum_ins_threshold
: autovacuum_vac_ins_thresh;
- anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
- ? relopts->analyze_scale_factor
+ anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+ ? avopts->analyze_scale_factor
: autovacuum_anl_scale;
- anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
- ? relopts->analyze_threshold
+ anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+ ? avopts->analyze_threshold
: autovacuum_anl_thresh;
- freeze_max_age = (relopts && relopts->freeze_max_age >= 0)
- ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age)
+ freeze_max_age = (avopts && avopts->freeze_max_age >= 0)
+ ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age)
: autovacuum_freeze_max_age;
- multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0)
- ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
+ multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0)
+ ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age)
: effective_multixact_freeze_max_age;
- av_enabled = (relopts ? relopts->enabled : true);
+ av_enabled = (avopts ? avopts->enabled : true);
/* Force vacuum if table is at risk of wraparound */
xidForceLimit = recentXid - freeze_max_age;
--
2.39.5 (Apple Git-154)
--QWBYbd5Ar5k8NvSv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
filename=v1-0002-autovac-resolve-relopts-before-vacuuming.patch
^ permalink raw reply [nested|flat] 802+ messages in thread
end of thread, other threads:[~2025-06-23 19:07 UTC | newest]
Thread overview: 802+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2003-08-13 05:23 Speeding up operations Rahul_Iyer <[email protected]>
2003-08-13 19:47 ` Frank Wiles <[email protected]>
2003-08-13 19:47 ` Rod Taylor <[email protected]>
2003-08-13 20:26 ` Tom Lane <[email protected]>
2003-08-13 22:42 ` Hannu Krosing <[email protected]>
2003-08-14 16:47 ` Matthew T. O'Connor <[email protected]>
2024-03-05 13:32 [PATCH v3 1/1] Use C99-designated initializer syntax for dispatch_table array Japin Li <[email protected]>
2024-03-05 13:32 [PATCH v2 1/1] Use C99-designated initializer syntax for dispatch_table array Japin Li <[email protected]>
2024-03-05 13:32 [PATCH v1 1/1] Use C99-designated initializer syntax for dispatch_table array Japin Li <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
2025-06-23 19:07 [PATCH v1 1/4] autovac: save all relopts instead of just avopts Nathan Bossart <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox